ホームに戻る
出典 :
関連 :
目次 :
ウィンドウを表示する手段
ウィンドウ( System.Windows.Window 、およびその派生クラス)はインスタンスが生成された時点では表示されず、
Show() または ShowDialog() メソッドを呼び出すなどで明示的に表示させる必要がある。
Window.Show() |
ウィンドウをモードレスウィンドウとして開く。 (開くと呼び元に制御を戻し、閉じるのを待機しない。) |
Window.ShowDialog() |
ウィンドウをモーダルウィンドウとして開く。 (ウィンドウが閉じるまで呼び元に制御を戻さない。) |
Show() に関する補足
Show() を呼び出すことは Window の Visibility を Visible に変更することと最終結果は変わらない。
即ち、Visibility を Visible に変更することでもモードレスウィンドウとして表示させることができるが、その振る舞いは Show() とは微妙に異なる。
Show() を呼び出す場合の例
private void DoSomething01()
{
// ウィンドウ生成
Window w = new Window();
// Loaded イベントのハンドラを登録
w.Loaded += delegate { System.Console.WriteLine("こちらが「先」に実行されます。"); };
// 表示( Show() 実行)
w.Show();
System.Console.WriteLine("こちらが「後」に実行されます。");
}
Visibility を変更する場合の例
private void DoSomething02()
{
// ウィンドウ生成
Window w = new Window();
// Loaded イベントのハンドラを登録
w.Loaded += delegate { System.Console.WriteLine("こちらが「後」に実行されるかもしれません。"); };
// 表示( Visibility 変更)
w.Visibility = Visibility.Visible;
System.Console.WriteLine("こちらが「先」に実行されるかもしれません。");
}
Console.WriteLine() の内容に注意されたい。これらは当該行の処理順を表している。
DoSomething01() 内で実行される Window.Show() は、新しく開かれた Window の Loaded イベントの発生(およびイベントハンドラ実行)後まで制御が戻らない(同期実行)。
しかし、DoSomething02() では Visibility の変更後即座に制御が戻る(非同期実行)ため、Loaded イベントの発生が DoSomething02() の実行後となる可能性がある(実行順が保証されない)。
実行結果( Window.DialogResult )
ShowDialog() の戻り値として返される(モーダル)ウィンドウの実行結果。プロパティとして取得、設定が可能である。
Nullable<Boolean> として宣言されており、既定値は false である。
設定には制約があり、以下の場合は InvalidOperationException 例外が発行される。
- モードレスウィンドウ( Show() で開く)に対して設定する
- ウィンドウが開かれる前に設定する
- ウィンドウが閉じられた後に設定する
(Windows Formsではモードレスでも DialogResult が設定・取得可能であり、とり得る値も異なる。)
オーナーウィンドウの設定(Window.Owner)
ウィンドウをモーダル表示した場合、新たに開くウィンドウと呼び元の(イベントハンドラを持つ)ウィンドウとは自動的には関連付けられない。
そうした場合、例えばタスクバーから呼び元のウィンドウを選択すると、そのウィンドウがアクティブとなってしまう。
(モーダル表示されているウィンドウが存在するため、操作はできない。)
このような現象を避けるには ShowDialog() を呼び出す前に、表示するウィンドウの Owner を明示的に指定する。
(Windows Formsでは自動的にオーナーが設定される点が異なる。)
// ボタン押下時の処理
// 新しいウィンドウを開く
private void Button_Click(object sender, RoutedEventArgs e)
{
// ウィンドウの生成・プロパティ設定
var wnd = new Window();
wnd.Title = "dynamic window #1";
wnd.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner;
wnd.Width = this.Width / 2;
wnd.Height = this.Height / 2;
// 新しいウィンドウの Owner を自身に指定する
wnd.Owner = this;
// ウィンドウを開く
wnd.ShowDialog();
}
現在アクティブなウィンドウを取得する方法
現在アクティブなウィンドウを取得する場合は、以下のように記述する(C#とLINQを使用)。
ここで、Application および Window はともに System.Windows 名前空間に属する。
var activeWindow = Application.Current.Windows
.OfType<Window>()
.SingleOrDefault(x => x.IsActive);
プロパティを操作することで、ウィンドウの外見や動作を変更することができる。詳細はリンク先を参照。
UIスレッドからモードレスウィンドウを開く場合の注意点
UIスレッド(UIイベントハンドラ)からウィンドウをモードレスで開く場合、実装によってはウィンドウが表示されない。
正しくないコード
// ボタンクリックハンドラ
private void Button_Click( object sender, RoutedEventArgs e )
{
try
{
// 処理中表示(モードレス)
WaitingScreen waiting = new ( "しばらくお待ちください…" );
waiting.Owner = this;
waiting.Show();
// (時間のかかる処理)
Task.Run( () => HeavyTask() ).Wait();
// 待機画面を閉じる
waiting.Close();
}
catch( Exception ex )
{
:
}
}
上記のコードでは、ボタンクリックを契機に時間のかかる処理を行い、その際に処理中である旨をモードレスウィンドウで表示しようとしている。
注意が必要な点として、Window.Show() によるモードレス表示はUIスレッドの終了後に行われることがあげられる。
(ウィンドウが表示されるためには、一旦呼び元に制御が戻る必要がある。)
ここでは HeavyTask() の終了を Task.Wait() で待機していることでUIスレッド( Button_Click() )がブロックされ、モードレスウィンドウが表示されない。
修正したコード
// ボタンクリックハンドラ( async )
private async void Button_Click( object sender, RoutedEventArgs e )
{
try
{
// 処理中表示(モードレス)
WaitingScreen waiting = new ( "しばらくお待ちください…" );
waiting.Owner = this;
waiting.Show();
// (時間のかかる処理 : await で待機)
await Task.Run( () => HeavyTask() );
// 待機画面を閉じる
waiting.Close();
}
catch( Exception ex )
{
:
}
}
Task.Wait() を await に置き換えている。
これにより、await に遭遇した時点で一旦UIスレッドが終了するため、想定通りの順序で処理が行われる。